home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / dev / cross / GBDK-2.0.lha / GBDK / examples / sound.c < prev    next >
C/C++ Source or Header  |  1998-10-01  |  22KB  |  845 lines

  1. #include <gb.h>
  2. #include <stdio.h>
  3. #include <console.h>
  4.  
  5. #define ARROW_CHAR 3
  6. #define SPACE_CHAR ' '
  7.  
  8. #define ARROW_X    0
  9. #define VAL_X      15
  10. #define TITLE_Y    0
  11. #define FIRST_X    (ARROW_X+1)
  12. #define FIRST_Y    (TITLE_Y+2)
  13.  
  14. #define PLAY       0x20
  15. #define FREQUENCY  0x21
  16.  
  17. #define MIN(x,y) ((x) > (y) ? (y) : (x))
  18. #define MAX(x,y) ((x) < (y) ? (y) : (x))
  19.  
  20. #define NB_MODES   5
  21.  
  22. enum notes {
  23.   C0, Cd0, D0, Dd0, E0, F0, Fd0, G0, Gd0, A0, Ad0, B0,
  24.   C1, Cd1, D1, Dd1, E1, F1, Fd1, G1, Gd1, A1, Ad1, B1,
  25.   C2, Cd2, D2, Dd2, E2, F2, Fd2, G2, Gd2, A2, Ad2, B2,
  26.   C3, Cd3, D3, Dd3, E3, F3, Fd3, G3, Gd3, A3, Ad3, B3,
  27.   C4, Cd4, D4, Dd4, E4, F4, Fd4, G4, Gd4, A4, Ad4, B4,
  28.   C5, Cd5, D5, Dd5, E5, F5, Fd5, G5, Gd5, A5, Ad5, B5,
  29.   SILENCE, END
  30. };
  31.  
  32. UWORD frequencies[] = {
  33.   44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986,
  34.   1046, 1102, 1155, 1205, 1253, 1297, 1339, 1379, 1417, 1452, 1486, 1517,
  35.   1546, 1575, 1602, 1627, 1650, 1673, 1694, 1714, 1732, 1750, 1767, 1783,
  36.   1798, 1812, 1825, 1837, 1849, 1860, 1871, 1881, 1890, 1899, 1907, 1915,
  37.   1923, 1930, 1936, 1943, 1949, 1954, 1959, 1964, 1969, 1974, 1978, 1982,
  38.   1985, 1988, 1992, 1995, 1998, 2001, 2004, 2006, 2009, 2011, 2013, 2015
  39. };
  40.  
  41. UBYTE music[] = {
  42.   C3, C3, G3, G3, A3, A3, G3, SILENCE,
  43.   F3, F3, E3, E3, D3, D3, C3, SILENCE,
  44.   G3, G3, F3, F3, E3, E3, D3, D3,
  45.   G3, G3, F3, F3, E3, E3, D3, D3,
  46.   C3, C3, G3, G3, A3, A3, G3, SILENCE,
  47.   F3, F3, E3, E3, D3, D3, C3, SILENCE,
  48.   END
  49. };
  50.  
  51. struct Params {
  52.   char *name;
  53.   UWORD max;
  54. };
  55.  
  56. struct Params params_0[] = {
  57.   { "Main Controls" , 0    },
  58.   { "All On/Off"    , 1    },
  59.   { "Vin->SO1"      , 1    },
  60.   { "Vin->SO2"      , 1    },
  61.   { "SO1 Volume"    , 7    },
  62.   { "SO2 Volume"    , 7    },
  63.   { NULL            , 0    }
  64. };
  65.  
  66. struct Params params_1[] = {
  67.   { "Sound Mode #1" , 0    },
  68.   { "Swp Time"      , 7    },
  69.   { "Swp Mode"      , 1    },
  70.   { "Swp Shifts"    , 7    },
  71.   { "Pat Duty"      , 3    },
  72.   { "Sound Len"     , 63   },
  73.   { "Env Init"      , 15   },
  74.   { "Env Mode"      , 1    },
  75.   { "Env Nb Swp"    , 7    },
  76.   { "Frequency"     , 2047 },
  77.   { "Cons Sel"      , 1    },
  78.   { "Out to SO1"    , 1    },
  79.   { "Out to SO2"    , 1    },
  80.   { "On/Off"        , 1    },
  81.   { NULL            , 0    }
  82. };
  83.  
  84. struct Params params_2[] = {
  85.   { "Sound Mode #2" , 0    },
  86.   { "Pat Duty"      , 3    },
  87.   { "Sound Len"     , 63   },
  88.   { "Env Init"      , 15   },
  89.   { "Env Mode"      , 1    },
  90.   { "Env Nb Step"   , 7    },
  91.   { "Frequency"     , 2047 },
  92.   { "Cons Sel"      , 1    },
  93.   { "Out to SO1"    , 1    },
  94.   { "Out to SO2"    , 1    },
  95.   { "On/Off"        , 1    },
  96.   { NULL            , 0    }
  97. };
  98.  
  99. struct Params params_3[] = {
  100.   { "Sound Mode #3" , 0    },
  101.   { "Sound On/Off"  , 1    },
  102.   { "Sound Len"     , 255  },
  103.   { "Sel Out Level" , 3    },
  104.   { "Frequency"     , 2047 },
  105.   { "Cons Sel"      , 1    },
  106.   { "Out to SO1"    , 1    },
  107.   { "Out to SO2"    , 1    },
  108.   { "On/Off"        , 1    },
  109.   { NULL            , 0    }
  110. };
  111.  
  112. struct Params params_4[] = {
  113.   { "Sound Mode #4" , 0    },
  114.   { "Sound Len"     , 63   },
  115.   { "Env Init"      , 15   },
  116.   { "Env Mode"      , 1    },
  117.   { "Env Nb Step"   , 7    },
  118.   { "Poly Cnt Freq" , 15   },
  119.   { "Poly Cnt Step" , 1    },
  120.   { "Poly Cnt Div"  , 7    },
  121.   { "Cons Sel"      , 1    },
  122.   { "Out to SO1"    , 1    },
  123.   { "Out to SO2"    , 1    },
  124.   { "On/Off"        , 1    },
  125.   { NULL            , 0    }
  126. };
  127.  
  128. struct Params *params_array[] = {
  129.   params_0,
  130.   params_1,
  131.   params_2,
  132.   params_3,
  133.   params_4,
  134. };
  135.  
  136. struct Params *params;
  137.  
  138. struct SoundReg {
  139.   struct {
  140.     /* 0xFF10 */
  141.     UBYTE sweepShifts     : 3;
  142.     UBYTE sweepMode       : 1;
  143.     UBYTE sweepTime       : 3;
  144.     UBYTE unused_1        : 1;
  145.  
  146.     /* 0xFF11 */
  147.     UBYTE soundLength     : 6;
  148.     UBYTE patternDuty     : 2;
  149.  
  150.     /* 0xFF12 */
  151.     UBYTE envNbSweep      : 3;
  152.     UBYTE envMode         : 1;
  153.     UBYTE envInitialValue : 4;
  154.  
  155.     /* 0xFF13 */
  156.     UBYTE frequencyLow;
  157.  
  158.     /* 0xFF14 */
  159.     UBYTE frequencyHigh   : 3;
  160.     UBYTE unused_2        : 3;
  161.     UBYTE counter_ConsSel : 1;
  162.     UBYTE restart         : 1;
  163.   } mode1;
  164.   struct {
  165.     /* 0xFF15 */
  166.     UBYTE unused_1;
  167.  
  168.     /* 0xFF16 */
  169.     UBYTE soundLength     : 6;
  170.     UBYTE patternDuty     : 2;
  171.  
  172.     /* 0xFF17 */
  173.     UBYTE envNbStep       : 3;
  174.     UBYTE envMode         : 1;
  175.     UBYTE envInitialValue : 4;
  176.  
  177.     /* 0xFF18 */
  178.     UBYTE frequencyLow;
  179.  
  180.     /* 0xFF19 */
  181.     UBYTE frequencyHigh   : 3;
  182.     UBYTE unused_2        : 3;
  183.     UBYTE counter_ConsSel : 1;
  184.     UBYTE restart         : 1;
  185.   } mode2;
  186.   struct {
  187.     /* 0xFF1A */
  188.     UBYTE unused_1        : 7;
  189.     UBYTE on_Off          : 1;
  190.  
  191.     /* 0xFF1B */
  192.     UBYTE soundLength;
  193.  
  194.     /* 0xFF1C */
  195.     UBYTE unused_2        : 5;
  196.     UBYTE selOutputLevel  : 2;
  197.     UBYTE unused_3        : 1;
  198.  
  199.     /* 0xFF1D */
  200.     UBYTE frequencyLow;
  201.  
  202.     /* 0xFF1E */
  203.     UBYTE frequencyHigh   : 3;
  204.     UBYTE unused_4        : 3;
  205.     UBYTE counter_ConsSel : 1;
  206.     UBYTE restart         : 1;
  207.   } mode3;
  208.   struct {
  209.     /* 0xFF1F */
  210.     UBYTE unused_1;
  211.  
  212.     /* 0xFF20 */
  213.     UBYTE soundLength     : 6;
  214.     UBYTE unused_2        : 2;
  215.  
  216.     /* 0xFF21 */
  217.     UBYTE envNbStep       : 3;
  218.     UBYTE envMode         : 1;
  219.     UBYTE envInitialValue : 4;
  220.  
  221.     /* 0xFF22 */
  222.     UBYTE polyCounterDiv  : 3;
  223.     UBYTE polyCounterStep : 1;
  224.     UBYTE polyCounterFreq : 4;
  225.  
  226.     /* 0xFF23 */
  227.     UBYTE unused_3        : 6;
  228.     UBYTE counter_ConsSel : 1;
  229.     UBYTE restart         : 1;
  230.   } mode4;
  231.   struct {
  232.     /* 0xFF24 */
  233.     UBYTE SO1_OutputLevel : 3;
  234.     UBYTE Vin_SO1         : 1;
  235.     UBYTE SO2_OutputLevel : 3;
  236.     UBYTE Vin_SO2         : 1;
  237.  
  238.     /* 0xFF25 */
  239.     UBYTE Sound1_To_SO1   : 1;
  240.     UBYTE Sound2_To_SO1   : 1;
  241.     UBYTE Sound3_To_SO1   : 1;
  242.     UBYTE Sound4_To_SO1   : 1;
  243.     UBYTE Sound1_To_SO2   : 1;
  244.     UBYTE Sound2_To_SO2   : 1;
  245.     UBYTE Sound3_To_SO2   : 1;
  246.     UBYTE Sound4_To_SO2   : 1;
  247.  
  248.     /* 0xFF26 */
  249.     UBYTE Sound1_On_Off   : 1;
  250.     UBYTE Sound2_On_Off   : 1;
  251.     UBYTE Sound3_On_Off   : 1;
  252.     UBYTE Sound4_On_Off   : 1;
  253.     UBYTE unused_1        : 3;
  254.     UBYTE global_On_Off   : 1;
  255.   } control;
  256. };
  257.  
  258. struct SoundReg *soundReg;
  259.  
  260. UWORD current_value(UBYTE mode, UBYTE line)
  261. {
  262.   if(mode == 0) {
  263.     switch(line)
  264.       {
  265.       case 0: /* global_On_Off */
  266.     return soundReg->control.global_On_Off;
  267.       case 1: /* Vin_SO1 */
  268.     return soundReg->control.Vin_SO1;
  269.       case 2: /* Vin_SO2 */
  270.     return soundReg->control.Vin_SO2;
  271.       case 3: /* SO1_OutputLevel */
  272.     return soundReg->control.SO1_OutputLevel;
  273.       case 4: /* SO2_OutputLevel */
  274.     return soundReg->control.SO2_OutputLevel;
  275.       }
  276.   } else if(mode == 1) {
  277.     switch(line)
  278.       {
  279.       case 0: /* sweepTime */
  280.     return soundReg->mode1.sweepTime;
  281.       case 1: /* sweepMode */
  282.     return soundReg->mode1.sweepMode;
  283.       case 2: /* sweepShifts */
  284.     return soundReg->mode1.sweepShifts;
  285.       case 3: /* patternDuty */
  286.     return soundReg->mode1.patternDuty;
  287.       case 4: /* soundLength */
  288.     return soundReg->mode1.soundLength;
  289.       case 5: /* envInitialValue */
  290.     return soundReg->mode1.envInitialValue;
  291.       case 6: /* envMode */
  292.     return soundReg->mode1.envMode;
  293.       case 7: /* envNbSweep */
  294.     return soundReg->mode1.envNbSweep;
  295.       case 8: /* frequency */
  296.       case FREQUENCY:
  297.     return ((UWORD)soundReg->mode1.frequencyHigh << 8) +
  298.       (UWORD)soundReg->mode1.frequencyLow;
  299.       case 9: /* counter_ConsSel */
  300.     return soundReg->mode1.counter_ConsSel;
  301.       case 10: /* Sound1_To_SO1 */
  302.     return soundReg->control.Sound1_To_SO1;
  303.       case 11: /* Sound1_To_SO2 */
  304.     return soundReg->control.Sound1_To_SO2;
  305.       case 12: /* Sound1_On_Off */
  306.     return soundReg->control.Sound1_On_Off;
  307.       }
  308.   } else if(mode == 2) {
  309.     switch(line)
  310.       {
  311.       case 0: /* patternDuty */
  312.     return soundReg->mode2.patternDuty;
  313.       case 1: /* soundLength */
  314.     return soundReg->mode2.soundLength;
  315.       case 2: /* envInitialValue */
  316.     return soundReg->mode2.envInitialValue;
  317.       case 3: /* envMode */
  318.     return soundReg->mode2.envMode;
  319.       case 4: /* envNbStep */
  320.     return soundReg->mode2.envNbStep;
  321.       case 5: /* frequency */
  322.       case FREQUENCY:
  323.     return ((UWORD)soundReg->mode2.frequencyHigh << 8) +
  324.       (UWORD)soundReg->mode2.frequencyLow;
  325.       case 6: /* counter_ConsSel */
  326.     return soundReg->mode2.counter_ConsSel;
  327.       case 7: /* Sound2_To_SO1 */
  328.     return soundReg->control.Sound2_To_SO1;
  329.       case 8: /* Sound2_To_SO2 */
  330.     return soundReg->control.Sound2_To_SO2;
  331.       case 9: /* Sound2_On_Off */
  332.     return soundReg->control.Sound2_On_Off;
  333.       }
  334.   } else if(mode == 3) {
  335.     switch(line)
  336.       {
  337.       case 0: /* on_Off */
  338.     return soundReg->mode3.on_Off;
  339.       case 1: /* soundLength */
  340.     return soundReg->mode3.soundLength;
  341.       case 2: /* selOutputLevel */
  342.     return soundReg->mode3.selOutputLevel;
  343.       case 3: /* frequency */
  344.       case FREQUENCY:
  345.     return ((UWORD)soundReg->mode3.frequencyHigh << 8) +
  346.       (UWORD)soundReg->mode3.frequencyLow;
  347.       case 4: /* counter_ConsSel */
  348.     return soundReg->mode3.counter_ConsSel;
  349.       case 5: /* Sound3_To_SO1 */
  350.     return soundReg->control.Sound3_To_SO1;
  351.       case 6: /* Sound3_To_SO2 */
  352.     return soundReg->control.Sound3_To_SO2;
  353.       case 7: /* Sound3_On_Off */
  354.     return soundReg->control.Sound3_On_Off;
  355.       }
  356.   } else if(mode == 4) {
  357.     switch(line)
  358.       {
  359.       case 0: /* soundLength */
  360.     return soundReg->mode4.soundLength;
  361.       case 1: /* envInitialValue */
  362.     return soundReg->mode4.envInitialValue;
  363.       case 2: /* envMode */
  364.     return soundReg->mode4.envMode;
  365.       case 3: /* envNbStep */
  366.     return soundReg->mode4.envNbStep;
  367.       case 4: /* polyCounterFreq */
  368.     return soundReg->mode4.polyCounterFreq;
  369.       case 5: /* polyCounterStep */
  370.     return soundReg->mode4.polyCounterStep;
  371.       case 6: /* polyCounterDiv */
  372.     return soundReg->mode4.polyCounterDiv;
  373.       case 7: /* counter_ConsSel */
  374.     return soundReg->mode4.counter_ConsSel;
  375.       case 8: /* Sound4_To_SO1 */
  376.     return soundReg->control.Sound4_To_SO1;
  377.       case 9: /* Sound4_To_SO2 */
  378.     return soundReg->control.Sound4_To_SO2;
  379.       case 10: /* Sound4_On_Off */
  380.     return soundReg->control.Sound4_On_Off;
  381.       }
  382.   }
  383.   return 0;
  384. }
  385.  
  386. void update_value(UBYTE mode, UBYTE line, UWORD value)
  387. {
  388.   if(mode == 0) {
  389.     switch(line)
  390.       {
  391.       case 0: /* global_On_Off */
  392.     soundReg->control.global_On_Off = value;
  393.     NR52_REG = ((UBYTE *)soundReg)[0x16];
  394.     break;
  395.       case 1: /* Vin_SO1 */
  396.     soundReg->control.Vin_SO1 = value;
  397.     NR50_REG = ((UBYTE *)soundReg)[0x14];
  398.     break;
  399.       case 2: /* Vin_SO2 */
  400.     soundReg->control.Vin_SO2 = value;
  401.     NR50_REG = ((UBYTE *)soundReg)[0x14];
  402.     break;
  403.       case 3: /* SO1_OutputLevel */
  404.     soundReg->control.SO1_OutputLevel = value;
  405.     NR50_REG = ((UBYTE *)soundReg)[0x14];
  406.     break;
  407.       case 4: /* SO2_OutputLevel */
  408.     soundReg->control.SO2_OutputLevel = value;
  409.     NR50_REG = ((UBYTE *)soundReg)[0x14];
  410.     break;
  411.       case FREQUENCY:
  412.     update_value(1, FREQUENCY, value);
  413.     update_value(2, FREQUENCY, value);
  414.     update_value(3, FREQUENCY, value);
  415.     break;
  416.       case PLAY: /* restart */
  417.     update_value(1, FREQUENCY, current_value(1, FREQUENCY));
  418.     update_value(2, FREQUENCY, current_value(2, FREQUENCY));
  419.     update_value(3, FREQUENCY, current_value(3, FREQUENCY));
  420.     soundReg->mode1.restart = value;
  421.     soundReg->mode2.restart = value;
  422.     soundReg->mode3.restart = value;
  423.     soundReg->mode4.restart = value;
  424.     NR14_REG = ((UBYTE *)soundReg)[0x04];
  425.     NR24_REG = ((UBYTE *)soundReg)[0x09];
  426.     NR34_REG = ((UBYTE *)soundReg)[0x0E];
  427.     NR44_REG = ((UBYTE *)soundReg)[0x13];
  428.     soundReg->mode1.restart = 0;
  429.     soundReg->mode2.restart = 0;
  430.     soundReg->mode3.restart = 0;
  431.     soundReg->mode4.restart = 0;
  432.     break;
  433.       }
  434.   } else if(mode == 1) {
  435.     switch(line)
  436.       {
  437.       case 0: /* sweepTime */
  438.     soundReg->mode1.sweepTime = value;
  439.     NR10_REG = ((UBYTE *)soundReg)[0x00];
  440.     break;
  441.       case 1: /* sweepMode */
  442.     soundReg->mode1.sweepMode = value;
  443.     NR10_REG = ((UBYTE *)soundReg)[0x00];
  444.     break;
  445.       case 2: /* sweepShifts */
  446.     soundReg->mode1.sweepShifts = value;
  447.     NR10_REG = ((UBYTE *)soundReg)[0x00];
  448.     break;
  449.       case 3: /* patternDuty */
  450.     soundReg->mode1.patternDuty = value;
  451.     NR11_REG = ((UBYTE *)soundReg)[0x01];
  452.     break;
  453.       case 4: /* soundLength */
  454.     soundReg->mode1.soundLength = value;
  455.     NR11_REG = ((UBYTE *)soundReg)[0x01];
  456.     break;
  457.       case 5: /* envInitialValue */
  458.     soundReg->mode1.envInitialValue = value;
  459.     NR12_REG = ((UBYTE *)soundReg)[0x02];
  460.     break;
  461.       case 6: /* envMode */
  462.     soundReg->mode1.envMode = value;
  463.     NR12_REG = ((UBYTE *)soundReg)[0x02];
  464.     break;
  465.       case 7: /* envNbSweep */
  466.     soundReg->mode1.envNbSweep = value;
  467.     NR12_REG = ((UBYTE *)soundReg)[0x02];
  468.     break;
  469.       case 8: /* frequency */
  470.       case FREQUENCY:
  471.     soundReg->mode1.frequencyHigh = value >> 8;
  472.     soundReg->mode1.frequencyLow  = value;
  473.     NR13_REG = ((UBYTE *)soundReg)[0x03];
  474.     NR14_REG = ((UBYTE *)soundReg)[0x04];
  475.     break;
  476.       case 9: /* counter_ConsSel */
  477.     soundReg->mode1.counter_ConsSel = value;
  478.     NR14_REG = ((UBYTE *)soundReg)[0x04];
  479.     break;
  480.       case 10: /* Sound1_To_SO1 */
  481.     soundReg->control.Sound1_To_SO1 = value;
  482.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  483.     break;
  484.       case 11: /* Sound1_To_SO2 */
  485.     soundReg->control.Sound1_To_SO2 = value;
  486.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  487.     break;
  488.       case 12: /* Sound1_On_Off */
  489.     soundReg->control.Sound1_On_Off = value;
  490.     NR52_REG = ((UBYTE *)soundReg)[0x16];
  491.     break;
  492.       case PLAY: /* restart */
  493.     update_value(mode, FREQUENCY, current_value(mode, FREQUENCY));
  494.     soundReg->mode1.restart = value;
  495.     NR14_REG = ((UBYTE *)soundReg)[0x04];
  496.     soundReg->mode1.restart = 0;
  497.     break;
  498.       }
  499.   } else if(mode == 2) {
  500.     switch(line)
  501.       {
  502.       case 0: /* patternDuty */
  503.     soundReg->mode2.patternDuty = value;
  504.     NR21_REG = ((UBYTE *)soundReg)[0x06];
  505.     break;
  506.       case 1: /* soundLength */
  507.     soundReg->mode2.soundLength = value;
  508.     NR21_REG = ((UBYTE *)soundReg)[0x06];
  509.     break;
  510.       case 2: /* envInitialValue */
  511.     soundReg->mode2.envInitialValue = value;
  512.     NR22_REG = ((UBYTE *)soundReg)[0x07];
  513.     break;
  514.       case 3: /* envMode */
  515.     soundReg->mode2.envMode = value;
  516.     NR22_REG = ((UBYTE *)soundReg)[0x07];
  517.     break;
  518.       case 4: /* envNbStep */
  519.     soundReg->mode2.envNbStep = value;
  520.     NR22_REG = ((UBYTE *)soundReg)[0x07];
  521.     break;
  522.       case 5: /* frequency */
  523.       case FREQUENCY:
  524.     soundReg->mode2.frequencyHigh = value >> 8;
  525.     soundReg->mode2.frequencyLow  = value;
  526.     NR23_REG = ((UBYTE *)soundReg)[0x08];
  527.     NR24_REG = ((UBYTE *)soundReg)[0x09];
  528.     break;
  529.       case 6: /* counter_ConsSel */
  530.     soundReg->mode2.counter_ConsSel = value;
  531.     NR24_REG = ((UBYTE *)soundReg)[0x09];
  532.     break;
  533.       case 7: /* Sound2_To_SO1 */
  534.     soundReg->control.Sound2_To_SO1 = value;
  535.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  536.     break;
  537.       case 8: /* Sound2_To_SO2 */
  538.     soundReg->control.Sound2_To_SO2 = value;
  539.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  540.     break;
  541.       case 9: /* Sound2_On_Off */
  542.     soundReg->control.Sound2_On_Off = value;
  543.     NR52_REG = ((UBYTE *)soundReg)[0x16];
  544.     break;
  545.       case PLAY: /* restart */
  546.     update_value(mode, FREQUENCY, current_value(mode, FREQUENCY));
  547.     soundReg->mode2.restart = value;
  548.     NR24_REG = ((UBYTE *)soundReg)[0x09];
  549.     soundReg->mode2.restart = 0;
  550.     break;
  551.       }
  552.   } else if(mode == 3) {
  553.     switch(line)
  554.       {
  555.       case 0: /* on_Off */
  556.     soundReg->mode3.on_Off = value;
  557.     NR30_REG = ((UBYTE *)soundReg)[0x0A];
  558.     break;
  559.       case 1: /* soundLength */
  560.     soundReg->mode3.soundLength = value;
  561.     NR31_REG = ((UBYTE *)soundReg)[0x0B];
  562.     break;
  563.       case 2: /* selOutputLevel */
  564.     soundReg->mode3.selOutputLevel = value;
  565.     NR32_REG = ((UBYTE *)soundReg)[0x0C];
  566.     break;
  567.       case 3: /* frequency */
  568.       case FREQUENCY:
  569.     soundReg->mode3.frequencyHigh = value >> 8;
  570.     soundReg->mode3.frequencyLow  = value;
  571.     NR33_REG = ((UBYTE *)soundReg)[0x0D];
  572.     NR34_REG = ((UBYTE *)soundReg)[0x0E];
  573.     break;
  574.       case 4: /* counter_ConsSel */
  575.     soundReg->mode3.counter_ConsSel = value;
  576.     NR34_REG = ((UBYTE *)soundReg)[0x0E];
  577.     break;
  578.       case 5: /* Sound3_To_SO1 */
  579.     soundReg->control.Sound3_To_SO1 = value;
  580.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  581.     break;
  582.       case 6: /* Sound3_To_SO2 */
  583.     soundReg->control.Sound3_To_SO2 = value;
  584.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  585.     break;
  586.       case 7: /* Sound3_On_Off */
  587.     soundReg->control.Sound3_On_Off = value;
  588.     NR52_REG = ((UBYTE *)soundReg)[0x16];
  589.     break;
  590.       case PLAY: /* restart */
  591.     update_value(mode, FREQUENCY, current_value(mode, FREQUENCY));
  592.     soundReg->mode3.restart = value;
  593.     NR34_REG = ((UBYTE *)soundReg)[0x0E];
  594.     soundReg->mode3.restart = 0;
  595.     break;
  596.       }
  597.   } else if(mode == 4) {
  598.     switch(line)
  599.       {
  600.       case 0: /* soundLength */
  601.     soundReg->mode4.soundLength = value;
  602.     NR41_REG = ((UBYTE *)soundReg)[0x10];
  603.     break;
  604.       case 1: /* envInitialValue */
  605.     soundReg->mode4.envInitialValue = value;
  606.     NR42_REG = ((UBYTE *)soundReg)[0x11];
  607.     break;
  608.       case 2: /* envMode */
  609.     soundReg->mode4.envMode = value;
  610.     NR42_REG = ((UBYTE *)soundReg)[0x11];
  611.     break;
  612.       case 3: /* envNbStep */
  613.     soundReg->mode4.envNbStep = value;
  614.     NR42_REG = ((UBYTE *)soundReg)[0x11];
  615.     break;
  616.       case 4: /* polyCounterFreq */
  617.     soundReg->mode4.polyCounterFreq = value;
  618.     NR43_REG = ((UBYTE *)soundReg)[0x12];
  619.     break;
  620.       case 5: /* polyCounterStep */
  621.     soundReg->mode4.polyCounterStep = value;
  622.     NR43_REG = ((UBYTE *)soundReg)[0x12];
  623.     break;
  624.       case 6: /* polyCounterDiv */
  625.     soundReg->mode4.polyCounterDiv = value;
  626.     NR43_REG = ((UBYTE *)soundReg)[0x12];
  627.     break;
  628.       case 7: /* counter_ConsSel */
  629.     soundReg->mode4.counter_ConsSel = value;
  630.     NR44_REG = ((UBYTE *)soundReg)[0x13];
  631.     break;
  632.       case 8: /* Sound4_To_SO1 */
  633.     soundReg->control.Sound4_To_SO1 = value;
  634.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  635.     break;
  636.       case 9: /* Sound4_To_SO2 */
  637.     soundReg->control.Sound4_To_SO2 = value;
  638.     NR51_REG = ((UBYTE *)soundReg)[0x15];
  639.     break;
  640.       case 10: /* Sound4_On_Off */
  641.     soundReg->control.Sound4_On_Off = value;
  642.     NR52_REG = ((UBYTE *)soundReg)[0x16];
  643.     break;
  644.       case PLAY: /* restart */
  645.     soundReg->mode4.restart = value;
  646.     NR44_REG = ((UBYTE *)soundReg)[0x13];
  647.     soundReg->mode4.restart = 0;
  648.     break;
  649.       }
  650.   }
  651. }
  652.  
  653. UBYTE draw_screen(UBYTE mode)
  654. {
  655.   UBYTE i;
  656.  
  657.   cls();
  658.   gotoxy(FIRST_X, TITLE_Y);
  659.   print(params[0].name);
  660.  
  661.   for(i = 0; params[i+1].name; i++) {
  662.     gotoxy(FIRST_X, FIRST_Y+i);
  663.     print(params[i+1].name);
  664.     gotoxy(VAL_X, FIRST_Y+i);
  665.     println(current_value(mode, i), 10, UNSIGNED);
  666.   }
  667.   return i-1;
  668. }
  669.  
  670.  
  671. void play_music(UBYTE mode)
  672. {
  673.   UBYTE i = 0;
  674.  
  675.   while(music[i] != END) {
  676.     if(music[i] != SILENCE) {
  677.       update_value(mode, FREQUENCY, frequencies[music[i]]);
  678.       update_value(mode, PLAY, 1);
  679.     }
  680.     delay(500);
  681.     i++;
  682.   }
  683. }
  684.  
  685. void dump_registers()
  686. {
  687.   UBYTE reg;
  688.   UBYTE i, j;
  689.  
  690.   cls();
  691.   gotoxy(FIRST_X, TITLE_Y);
  692.   print("Register Dump");
  693.  
  694.   for(i = 0, j = 0; i <= 0x16; i++, j++) {
  695.     if(i == 0x05 || i == 0x0F)
  696.       i++;
  697.     if(j%2 == 0) {
  698.       gotoxy(FIRST_X, FIRST_Y+j/2);
  699.       print("0xFF");
  700.     } else {
  701.       gotoxy(FIRST_X+6, FIRST_Y+j/2);
  702.       putchar('-');
  703.     }
  704.     printn(i+0x10, 16, UNSIGNED);
  705.     if(j%2 == 0) {
  706.       gotoxy(VAL_X, FIRST_Y+j/2);
  707.     } else {
  708.       gotoxy(VAL_X+2, FIRST_Y+j/2);
  709.       putchar('-');
  710.     }
  711.     reg = ((UBYTE *)soundReg)[i];
  712.     if(!(reg & 0xF0U)) putchar('0');
  713.     printn(reg, 16, UNSIGNED);
  714.   }
  715. }
  716.  
  717. void wait_event(UBYTE mode)
  718. {
  719.   UBYTE input, y, last_y;
  720.   UWORD l;
  721.  
  722.   while(1) {
  723.     params = params_array[mode];
  724.     last_y = draw_screen(mode) + FIRST_Y;
  725.     y = FIRST_Y;
  726.     gotoxy(ARROW_X, y);
  727.     setchar(ARROW_CHAR);
  728.  
  729.     while(1) {
  730.       input = joypad();
  731.       if(input & J_UP) {
  732.     gotoxy(ARROW_X, y); setchar(SPACE_CHAR);
  733.     if(--y < FIRST_Y)
  734.       y = last_y;
  735.     gotoxy(ARROW_X, y); setchar(ARROW_CHAR);
  736.       } else if(input & J_DOWN) {
  737.     gotoxy(ARROW_X, y); setchar(SPACE_CHAR);
  738.     if(++y > last_y)
  739.       y = FIRST_Y;
  740.     gotoxy(ARROW_X, y); setchar(ARROW_CHAR);
  741.       } else if(input & J_LEFT) {
  742.     l = current_value(mode, y-FIRST_Y);
  743.     if(l > 0) {
  744.       if(input & J_A)
  745.         l = MAX(l, 10) - 10;
  746.       else if(input & J_B)
  747.         l = 0;
  748.       else
  749.         l--;
  750.       update_value(mode, y-FIRST_Y, l);
  751.       gotoxy(VAL_X, y); print("    ");
  752.       gotoxy(VAL_X, y); println(l, 10, UNSIGNED);
  753.     }
  754.       } else if(input & J_RIGHT) {
  755.     l = current_value(mode, y-FIRST_Y);
  756.     if(l < params[y-(FIRST_Y-1)].max) {
  757.       if(input & J_A)
  758.         l = MIN(l + 10, params[y-(FIRST_Y-1)].max);
  759.       else if(input & J_B)
  760.         l = params[y-(FIRST_Y-1)].max;
  761.       else
  762.         l++;
  763.       update_value(mode, y-FIRST_Y, l);
  764.       gotoxy(VAL_X, y); print("    ");
  765.       gotoxy(VAL_X, y); println(l, 10, UNSIGNED);
  766.     }
  767.       } else if(input & J_START) {
  768.     if(input & J_A)
  769.       play_music(mode);
  770.     else
  771.       update_value(mode, PLAY, 1);
  772.     waitpadup();
  773.       } else if(input & J_SELECT) {
  774.     if(input & J_A)
  775.       dump_registers();
  776.     else
  777.       mode = (mode+1) % NB_MODES;
  778.     waitpadup();
  779.     break;
  780.       }
  781.       delay(250);
  782.     }
  783.   }
  784. }
  785.  
  786. void main()
  787. {
  788.   struct SoundReg s = {
  789.     { 0, 0, 0, 0,
  790.       1, 2,
  791.       3, 0, 4,
  792.       0x73U,
  793.       6, 0, 0, 0 },
  794.     { 0,
  795.       1, 2,
  796.       4, 0, 8,
  797.       0xD7U,
  798.       6, 0, 0, 0 },
  799.     { 0, 1,
  800.       0,
  801.       0, 1, 0,
  802.       0xD6U,
  803.       6, 0, 0, 0 },
  804.     { 0,
  805.       58, 0,
  806.       1, 0, 10,
  807.       0, 0, 0,
  808.       0, 1, 0 },
  809.     { 7, 0, 7, 0,
  810.       1, 1, 1, 1, 1, 1, 1, 1,
  811.       0, 0, 0, 0, 0, 1 }
  812.   };
  813.  
  814.   soundReg = &s;
  815.   NR10_REG = ((UBYTE *)soundReg)[0x00];
  816.   NR11_REG = ((UBYTE *)soundReg)[0x01];
  817.   NR12_REG = ((UBYTE *)soundReg)[0x02];
  818.   NR13_REG = ((UBYTE *)soundReg)[0x03];
  819.   NR14_REG = ((UBYTE *)soundReg)[0x04];
  820.  
  821.   NR21_REG = ((UBYTE *)soundReg)[0x06];
  822.   NR22_REG = ((UBYTE *)soundReg)[0x07];
  823.   NR23_REG = ((UBYTE *)soundReg)[0x08];
  824.   NR24_REG = ((UBYTE *)soundReg)[0x09];
  825.  
  826.   NR30_REG = ((UBYTE *)soundReg)[0x0A];
  827.   NR31_REG = ((UBYTE *)soundReg)[0x0B];
  828.   NR32_REG = ((UBYTE *)soundReg)[0x0C];
  829.   NR33_REG = ((UBYTE *)soundReg)[0x0D];
  830.   NR34_REG = ((UBYTE *)soundReg)[0x0E];
  831.  
  832.   NR41_REG = ((UBYTE *)soundReg)[0x10];
  833.   NR42_REG = ((UBYTE *)soundReg)[0x11];
  834.   NR43_REG = ((UBYTE *)soundReg)[0x12];
  835.   NR44_REG = ((UBYTE *)soundReg)[0x13];
  836.  
  837.   NR50_REG = ((UBYTE *)soundReg)[0x14];
  838.   NR51_REG = ((UBYTE *)soundReg)[0x15];
  839.   NR52_REG = ((UBYTE *)soundReg)[0x16];
  840.  
  841.   cls();
  842.  
  843.   wait_event(1);
  844. }
  845.